﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using PmSoft.Web.Abstractions.Middlewares;
using PmSoft.Web.Abstractions.Notifications;
using System.Text;

namespace PmSoft.Web.Abstractions.Authorization;

public static class AuthorizationExtensions
{
	/// <summary>
	/// 添加 PmSoft 授权相关的服务到依赖注入容器
	/// </summary>
	/// <param name="services">服务集合</param>
	/// <param name="configuration">配置对象，用于读取 JWT 配置</param>
	/// <returns>服务集合</returns>
	public static IServiceCollection AddPmSoftAuthorization(this IServiceCollection services, IConfiguration configuration)
	{
		// 注册 JWT 服务
		services.AddScoped<IJwtService, JwtService>();

		// 注册自定义的授权处理器
		services.AddScoped<IAuthorizationHandler, MenuAuthorizationHandler>();

		// 注册菜单权限检查器（缓存版）
		services.AddScoped<CachedMenuPermissionChecker>();

		// 注册菜单权限检查器（数据库版）
		services.AddScoped<DatabaseMenuPermissionChecker>();

		// 注册当前用户中间件
		services.AddScoped<CurrentUserMiddleware>();

		// 注册 HttpContext 访问器，用于在服务中访问当前请求的 HttpContext
		services.AddHttpContextAccessor();

		// 配置 JWT 认证
		services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
		   .AddJwtBearer(options =>
		   {
			   // 配置 JWT 令牌验证参数
			   options.TokenValidationParameters = new TokenValidationParameters
			   {
				   ValidateIssuer = true, // 验证签发者
				   ValidateAudience = true, // 验证接收者
				   ValidateLifetime = true, // 验证令牌有效期
				   ValidateIssuerSigningKey = true, // 验证签名密钥
				   ValidIssuer = configuration["Jwt:Issuer"], // 合法的签发者
				   ValidAudience = configuration["Jwt:Audience"], // 合法的接收者
				   IssuerSigningKey = new SymmetricSecurityKey( // 签名密钥
					   Encoding.UTF8.GetBytes(configuration["Jwt:SecretKey"] ?? string.Empty))
			   };
			   // 为 SignalR 配置从查询字符串中提取 JWT 令牌
			   options.Events = new JwtBearerEvents
			   {
				   OnMessageReceived = context =>
				   {
					   var accessToken = context.Request.Query["access_token"];
					   var path = context.HttpContext.Request.Path;

					   // 仅对 SignalR Hub 请求处理令牌
					   if (!string.IsNullOrEmpty(accessToken)
					   && path.StartsWithSegments(NotificationSettings.ChatHubPath))
					   {
						   context.Token = accessToken;
					   }
					   return Task.CompletedTask;
				   }
			   };
		   });

		// 配置授权策略
		services.AddAuthorization(options =>
		{
			// 添加名为 "MenuPolicy" 的授权策略
			options.AddPolicy("MenuPolicy",
			  policy => policy.Requirements.Add(new MenuAuthorizationRequirement()));
		});

		return services;
	}

	/// <summary>
	/// 使用 PmSoft 授权相关的中间件
	/// </summary>
	/// <param name="builder">应用程序构建器</param>
	/// <returns>应用程序构建器</returns>
	public static IApplicationBuilder UsePmSoftAuthorization(this IApplicationBuilder builder)
	{

		// 使用自定义的当前用户中间件
		builder.UseCurrentUser();

		// 使用自定义的未授权响应格式中间件
		builder.UseCustomUnauthorized();

		// 使用身份验证中间件
		builder.UseAuthentication();

		// 使用授权中间件
		builder.UseAuthorization();

		return builder;
	}
}